package bayes;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import bayes.nodeTypes.Climate;
import bayes.nodeTypes.IceCondition;
import bayes.nodeTypes.IceSense;
import bayes.nodeTypes.Variable;
import domain.Board_Ass4;


public class Main_Bayes {

	public static final String BOARD_FILE 	= "board_Ass4_a.txt";
	public static final String CONFIG_FILE 	= "Ass4_config_a.txt";

	//public static final String BOARD_FILE 	= "board_Ass4_simple.txt";
	//public static final String CONFIG_FILE 	= "Ass4_config_simple.txt";

	public static void main(String[] args) {
		boolean stop = false;

		Board_Ass4 board 	= new Board_Ass4(BOARD_FILE, "4");
		BayesNetwork bn 	= new BayesNetwork(board, CONFIG_FILE);



		// sensing:
		//bn.readSensor(4, 7, true);
		//bn.readSensor(4, 7, true);
		//bn.readSensor(5, 14, false);
		bn.readSensor(1, 4, false);
		//bn.readSensor(4, 7, false);
		bn.print();

		question_1_2(bn);

		question_3(bn);


		while(!stop){
			Variable queryVariable		= null;
			Variable queryEvidence		= null;
			Evidence evidence			= null;
			System.out.println("\n***\nPlease select query: {1 to 5} or any thing else to exit:\n***");
			switch (readSelect()) {
				case 1:

					queryVariable 	= bn.get_root().getVariable();
					queryEvidence 	= bn.get_regions(1).getVariable();
					evidence 		= new Evidence(queryEvidence, Climate.COLD);	// replace COLD with WARM/FRIGID
					System.out.println();
					break;

				case 2:

					queryVariable 	= bn.get_root().getVariable();
					queryEvidence 	= bn.get_regions(1).getVariable();
					evidence 		= new Evidence(queryEvidence, Climate.COLD);
					break;

				case 3:

					queryVariable	= bn.get_site(0).getVariable();
					queryEvidence	= bn.get_regions(1).getVariable();
					evidence 		= new Evidence(queryEvidence, Climate.FRIGID);
					break;

				case 4:

					queryVariable 	= bn.get_root().getVariable();
					queryEvidence	= bn.get_site(0).getVariable();
					//queryEvidence1= bn.get_regions(1).getVariable();
					evidence 		= new Evidence(queryEvidence, IceCondition.ICY);
					//evidence.extend(queryEvidence1, Climate.WARM);
					break;

				case 5:

					queryVariable 	= bn.get_root().getVariable();
					queryEvidence	= bn.get_site(0).getVariable();
					//queryEvidence1= bn.get_regions(1).getVariable();
					evidence 		= new Evidence(queryEvidence, IceCondition.ICY);
					//evidence.extend(queryEvidence1, Climate.WARM);
					break;

				default:
					System.out.println("\n\tBye");
					System.exit(0);
					break;

			}
			Enumeration.runEnumerationAlgorithm(queryVariable, evidence, bn);
		}
	}


	private static void question_1_2(BayesNetwork bn) {
		int    question_2_ans_sniffer               = 0;
		double question_2_highestProbabilityIcySite = 0;

		System.out.println("\nAnswer To Question 1:\n=====================");
		// Question 1's answer:
		Evidence evidenceQ1 = null;
		for (int i = 0; i < bn.getNuberOfsites(); i++) {
			Node site = bn.get_site(i);

			// the query's variable:
			IceCondition siteVar = (IceCondition)site.getVariable();

			// the query's evidence:
			evidenceQ1 = new Evidence();
			for (Iterator<Node> iterator = bn.get_measurements().iterator(); iterator.hasNext();) {
				Node measure = iterator.next();
				IceSense variable = (IceSense)measure.getVariable();
				evidenceQ1.extend(variable, variable.get_measurement());
			}
			/*
			if (site.getNumberOfChildren() == 0) {
				evidenceQ1 = new Evidence();
			} else if (site.getNumberOfChildren() == 1) {
				IceSense variable0 = (IceSense) site.get_child(0).getVariable();
				evidenceQ1 = new Evidence(variable0, variable0.get_measurement());
			} else if (site.getNumberOfChildren() == 2) {
				IceSense variable0 = (IceSense) site.get_child(0).getVariable();
				IceSense variable1 = (IceSense) site.get_child(1).getVariable();
				evidenceQ1 = new Evidence(variable0, variable0.get_measurement());
				evidenceQ1.extend(variable1, variable1.get_measurement());
			}
			*/
			Distribution distri = Enumeration.runEnumerationAlgorithm(siteVar, evidenceQ1, bn);
			if (distri.getProbabilityOf(IceCondition.ICY) > question_2_highestProbabilityIcySite){
				question_2_highestProbabilityIcySite = distri.getProbabilityOf(IceCondition.ICY);
				question_2_ans_sniffer = i;
			}
		}

		System.out.println("\nAnswer To Question 2:\n============================\n" +
				"\tThe single highest probability of site to be Icy: site "+
				question_2_ans_sniffer+ "\n\tthat is with posterior probability: "+
				question_2_highestProbabilityIcySite);
	}

	
	//Answering question 3
	private static void question_3(BayesNetwork bn) {
		System.out.println("\n\nAnswer To Question 3:\n=====================");

		int numberOfSites = bn.getNuberOfsites();
		if (numberOfSites < 2){
			System.out.println("Question 3 will not be calculated. Less then two sites was found");
		}
		else{
			double highestScore = 0;
			int var_0=0, var_1=1;
			for (int i = 0; i < numberOfSites-1; i++) {
				for (int j = i+1; j < numberOfSites; j++) {
					double jointDistIcy = calculateJointDistribution(bn, i, j);
					if (jointDistIcy > highestScore){
						highestScore = jointDistIcy;
						var_0 = i;
						var_1 = j;
					}
				}
			}
			System.out.println("\nQuestion 3: The couple with highest probability to have ice is: "+var_0+", "+var_1 +
					"\n  \tthat is with posterior probability: "+highestScore);
		}
	}

	private static double calculateJointDistribution(BayesNetwork bn, int i, int j) {
		Variable varA = bn.get_site(i).getVariable();
		Variable varB = bn.get_site(j).getVariable();

		Evidence evidenceQ2 = new Evidence();
		for (Iterator<Node> iterator = bn.get_measurements().iterator(); iterator.hasNext();) {
			Node measure = iterator.next();
			IceSense variable = (IceSense)measure.getVariable();
			evidenceQ2.extend(variable, variable.get_measurement());
		}

		Evidence evidenceQ2_A  = new Evidence(evidenceQ2);
		Evidence evidenceQ2_B  = new Evidence(evidenceQ2);
		/*     ans     =    left    *  right     */
		/* P(A,B | C)  = P(A | B,C) * P(B | C)   */
		evidenceQ2_A.extend(varB, IceSense.SENSE_ICY);
		Distribution leftDist  = Enumeration.runEnumerationAlgorithm(varA, evidenceQ2_A, bn);
		Distribution rightDist = Enumeration.runEnumerationAlgorithm(varB, evidenceQ2_B, bn);
		//next line break's the abstraction
		double jointDistIcy = leftDist.getProbabilityOf(0) * rightDist.getProbabilityOf(0);
		return jointDistIcy;//System.out.println("Joint distrinution : " + jointDistIcy);
	}

	public static int readSelect(){
		BufferedReader userRead = new BufferedReader(new InputStreamReader(System.in));
		try {
			String lineIn = userRead.readLine();
			int selection = new Integer(lineIn);
			return selection;
		} catch (IOException e) {
			System.err.println("There might be a problem with the input...exiting the program");
			e.printStackTrace();
		}
		return -1;
	}
}
